use core::ptr::null_mut;
use msgbus::capi::{call, get_bus, init_bus, publish, subscribe, unsubscribe, MessageBusCallback};

extern "C" fn cb_handle(
    topic: *const libc::c_char,
    content: *const libc::c_char,
    _content_len: libc::c_int,
    args: *mut libc::c_void,
) {
    static mut COUNT: u32 = 0;
    unsafe {
        let owner = args as *const libc::c_char;
        if COUNT % 1 == 0 {
            libc::printf(
                b"%s: topic %s content %s\n\0".as_ptr() as *const libc::c_char,
                owner,
                topic,
                content,
            );
        }
        COUNT += 1;
    }
}

extern "C" fn cb_call(
    topic: *const libc::c_char,
    method: *const libc::c_char,
    content: *const libc::c_char,
    content_len: libc::c_int,
    args: *mut libc::c_void,
    data_len: *mut libc::c_int,
) -> *mut libc::c_char {
    let size = content_len as usize + 256;
    unsafe {
        let owner = args as *const libc::c_char;
        let buff = libc::malloc(size) as *mut libc::c_char;
        libc::memset(buff as *mut libc::c_void, 0, size);
        let l = libc::snprintf(
            buff,
            size,
            b"%s topic %s call %s content %s\n\0".as_ptr() as *const libc::c_char,
            owner,
            topic,
            method,
            content as *const libc::c_char,
        );
        *buff.offset(l as isize) = 0;
        if !data_len.is_null() {
            *data_len = size as libc::c_int;
        }
        buff
    }
}

fn main() {
    init_bus(10000);
    let bus = get_bus();
    let topic = b"aa/bb\0";
    let topic1 = b"aa/cc\0";
    let callback = MessageBusCallback {
        handle: Some(cb_handle),
        call: Some(cb_call),
        destroy: None,
    };
    let token = subscribe(
        bus,
        topic.as_ptr() as *const libc::c_char,
        callback,
        b"subscribe1\0".as_ptr() as *mut libc::c_void,
    );
    let token1 = subscribe(
        bus,
        topic1.as_ptr() as *const libc::c_char,
        callback,
        b"subscribe2\0".as_ptr() as *mut libc::c_void,
    );
    unsafe {
        libc::printf(
            b"subscribe token %s token1 %s\n\0".as_ptr() as *const libc::c_char,
            token,
            token1,
        );
    }
    let _ = get_bus();
    let _ = embed_std::thread::spawn(move || {
        for i in 0..2000 {
            let content = format!("hellow world {}\0", i);
            publish(
                get_bus(),
                topic.as_ptr() as *const libc::c_char,
                content.as_ptr() as *const libc::c_char,
                content.len() as i32,
                1000,
            );
            if i % 100 == 0 {
                std::thread::sleep(std::time::Duration::from_millis(10));
            }
        }
        for i in 0..1000 {
            let content = format!("hellow world {}\0", i);
            let mut data_len = 0i32;
            let mut data = null_mut::<libc::c_char>();
            let ret = call(
                get_bus(),
                topic.as_ptr() as *const libc::c_char,
                b"echo\0".as_ptr() as *const libc::c_char,
                content.as_ptr() as *const libc::c_char,
                content.len() as i32,
                &mut data,
                &mut data_len,
                1000,
            );
            if ret == 0 && !data.is_null() && data_len > 0 {
                unsafe {
                    libc::printf(
                        b"call return %d: %s\n\0".as_ptr() as *const i8,
                        data_len,
                        data,
                    );
                    libc::free(data as *mut libc::c_void);
                }
            }
            if i % 100 == 0 {
                std::thread::sleep(std::time::Duration::from_millis(10));
            }
        }
    });
    std::thread::sleep(std::time::Duration::from_millis(500));
    for _i in 0..100 {
        std::thread::sleep(std::time::Duration::from_secs(1));
    }
    unsafe {
        libc::printf(b"unsubscribe %s\n\0".as_ptr() as *const libc::c_char, token);
        unsubscribe(bus, token);
        libc::free(token as *mut libc::c_void);
    }
    if !token1.is_null() {
        unsafe {
            libc::free(token1 as *mut libc::c_void);
        }
    }
}
